#include <stdio.h>
#include <modbus/modbus.h>
#include <modbus/modbus-rtu.h>
#include <modbus/modbus-tcp.h>
#include <modbus/modbus-version.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/msg.h>
#include <errno.h>

union da
{
    int i_data;
    float f_data;
};

typedef struct msg
{
    char dev_name[32];
    int type;
    union da data;
    float tem;
    float hum;
} MSG_t;

modbus_t *ctx;
pthread_t tid;
MSG_t msg,met;
key_t shmkey, msgkey;
int shmid, msgid;
MSG_t *p = NULL;
void shm_init();
void msg_init();

void *thread(void *arg)
{
    msg.type = 0;
    while (1)
    {
        msgrcv(msgid, &msg, sizeof(msg), 0, 0);
        if (!strcmp("led", msg.dev_name))
            modbus_write_bit(ctx, 0, msg.data.i_data);
        else if (!strcmp("beep", msg.dev_name))
            modbus_write_bit(ctx, 1, msg.data.i_data);
    }
    return NULL;
}

int main(int argc, char const *argv[])
{
    shm_init();
    msg_init();
    ctx = modbus_new_tcp(argv[1], 502);
    if (ctx == NULL)
    {
        printf("init err");
        return -1;
    }
    modbus_set_slave(ctx, 1);
    if (modbus_connect(ctx) < 0)
    {
        printf("connect err\n");
        modbus_free(ctx);
        return -1;
    }
    printf("connect success\n");
    pthread_create(&tid, NULL, thread, NULL);
    pthread_detach(tid);
    uint16_t data[4];
    while (1)
    {
        modbus_read_registers(ctx, 0, 4, data);
        met.tem = modbus_get_float_dcba(data);
        met.hum = modbus_get_float_dcba(data + 2);
        p->tem = met.tem;
        p->hum = met.hum;
        sleep(1);
    }
    shmdt(p);
    shmctl(shmid, IPC_RMID, NULL);
    msgctl(msgid, IPC_RMID, NULL);
    return 0;
}

void shm_init()
{
    shmkey = ftok("./file", 'g');
    if (shmkey < 0)
    {
        perror("ftok err");
        return;
    }
    shmid = shmget(shmkey, 256, IPC_CREAT | IPC_EXCL | 0777);
    if (shmid < 0)
    {
        if (errno == EEXIST)
        {
            shmid = shmget(shmkey, 256, 0777);
        }
        else
        {
            perror("shmget err");
            return;
        }
    }
    p = shmat(shmid, NULL, 0);
    if (p == (MSG_t *)-1)
    {
        perror("shmat err");
        return;
    }
}

void msg_init()
{
    msgkey = ftok("./test", 'y');
    if (msgkey < 0)
    {
        perror("ftok err");
        return;
    }
    msgid = msgget(msgkey, IPC_CREAT | IPC_EXCL | 0777);
    if (msgid < 0)
    {
        if (errno == EEXIST)
        {
            msgid = msgget(msgkey, 0777);
        }
        else
        {
            perror("msgget err");
            return;
        }
    }
}